# es检索（）

from elasticsearch import Elasticsearch



class ESRetriever:
    """Elasticsearch检索工具类，专注于关键字检索"""

    def __init__(self):
        # 创建es连接
        try:
            self.es = Elasticsearch(hosts="http://localhost:9200")
            if not self.es.ping():
                raise ConnectionError("Could not connect to Elasticsearch")
            self.index_name = "resumes"     # 定义es中使用的索引名称-用于存储和检索简历数据
            self._init_index()      # 检查并创建索引
        except Exception as e:
            print(f"Error connecting to Elasticsearch: {e}")

    def refresh_index(self):
        """
        强制刷新 Elasticsearch 索引，确保新文档立即可检索
        """
        self.es.indices.refresh(index=self.index_name)

    def _init_index(self):
        """初始化ES索引结构"""        # 索引类似数据库的表
        if not self.es.indices.exists(index=self.index_name):
            self.es.indices.create(
                index=self.index_name,
                # 数据结构 提供索引的映射定义
                body={
                    "mappings": {
                        "properties": {
                            "job_id": {"type": "keyword"},
                            "resume_id": {"type": "keyword"},
                            "name": {"type": "text", "analyzer": "ik_max_word"},
                            "skills": {"type": "text", "analyzer": "ik_max_word"},
                            "education": {"type": "keyword"},
                            "work_experience": {"type": "text", "analyzer": "ik_max_word"}
                        }
                    }
                }
            )
            # self.es.get(index="resumes", id=resume_id)  根据简历id返回整个文档内容

    # 职位id 简历id 结构化处理的结构化文本
    def sync_document(self,job_id, resume_id, structured_data):
        """同步文档到ES"""
        # 1.构造es文档/行  写入es文档
        doc = {
            "job_id":job_id,
            "resume_id": resume_id,
            "name": structured_data["name"],
            "skills": structured_data["skills"],
            "education": structured_data["education"],
            "work_experience": structured_data["work_experience"]
        }
        self.es.index(index=self.index_name, id=resume_id, document=doc)

    # es_retriever.py
    def search(self, query_text, resume_ids=None, top_k=20):
        # 初始化 bool 查询的 must 条件
        must_clauses = []
        if resume_ids:
            # 确保 resume_ids 是列表，且元素为字符串
            if not isinstance(resume_ids, list):
                resume_ids = [str(resume_ids)]
            # 转换为字符串（避免 ES 类型不匹配）
            resume_ids = [str(rid) for rid in resume_ids]
            must_clauses.append({"terms": {"resume_id": resume_ids}})

        query = {
            "query": {
                "bool": {
                    "should": [
                        {"match": {"skills": {"query": query_text, "boost": 4}}},
                        {"match": {"work_experience": {"query": query_text, "boost": 3}}},
                        {"match": {"education": {"query": query_text, "boost": 2}}},
                        {"match": {"content": {"query": query_text, "boost": 1}}},

                        # 新增：模糊匹配和短语匹配，提高召回率
                        {"match_phrase": {"content": {"query": query_text, "boost": 2, "slop": 5}}},
                        {"match": {"content": {"query": query_text, "operator": "or", "fuzziness": "AUTO"}}},
                    ],
                    "minimum_should_match": 1  # 至少命中 1 个条件
                }
            },
            "size": top_k
        }

        try:
            result = self.es.search(index=self.index_name, body=query)
        except Exception as e:
            # 详细日志，方便调试
            print(f"ES 查询失败: {e}")
            print(f"查询体: {query}")
            return {}

        return {
            str(hit["_source"]["resume_id"]): hit["_score"]
            for hit in result["hits"]["hits"]
        }

eskeyword = ESRetriever()